<?php

namespace IDock\Http;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class Request extends RequestConfig
{
    protected $headers = [];

    protected $method;

    protected $format = '';

    protected $async = false;

    protected $cookie = '';

    protected $preParameter;

    protected $bizParam;

    protected $requestId;

    protected $response;

    protected $visitor;

    protected $inLog = true;

    protected $option;

    protected $errorThrow = true;

    public function loadConfig(array $config): Request
    {
        return $this;
    }

    public function setHeaders(array $headers): Request
    {
        $this->headers = $headers;
        return $this;
    }

    public function getHeaders(): array
    {
        return $this->headers;
    }

    public function setMethod(string $method): Request
    {
        $this->method = $method;
        return $this;
    }

    public function setAsync(bool $async): Request
    {
        $this->async = $async;
        return $this;
    }

    public function setCookie(string $cookie): Request
    {
        $this->cookie = $cookie;
        return $this;
    }

    public function getPreParameter()
    {
        return $this->preParameter;
    }

    public function setPreParameter($preParameter): void
    {
        $this->preParameter = $preParameter;
    }

    /**
     * @param mixed $requestId
     */
    public function setRequestId($requestId): void
    {
        $this->requestId = $requestId;
    }

    /**
     * @return mixed
     */
    public function getRequestId()
    {
        return $this->requestId;
    }

    public function setVisitor($visitor)
    {
        $this->visitor = $visitor;
    }

    /**
     * @return mixed
     */
    public function getBizParam()
    {
        return $this->bizParam;
    }

    /**
     * @param mixed $bizParam
     */
    public function setBizParam($bizParam): void
    {
        $this->bizParam = $bizParam;
    }

    /**
     * @return mixed
     */
    public function getResponse()
    {
        return $this->response;
    }

    /**
     * @return mixed
     */
    public function getVisitor()
    {
        return $this->visitor;
    }

    public function generate() :array
    {
        return  [];
    }

    public function request(Request $request,Response $multiplexResponse = null): Response
    {
        $this->buildOptions();
        $this->buildMethod();
        $this->buildUrl();
        $this->mkLogsDir();

        $request->requestLogs($request->requestId,$this->inLog);

        if (!$multiplexResponse) {
            $response = $request->getResponse();

            $response = new $response;
        } else {
            $response = $multiplexResponse;
        }
        //-----
        //-----
        //测试
        if ($GLOBALS['testResponse'] ?? '') {
            $string = $GLOBALS['testResponse'];
            $response->setBody($string);
            $response->setCode('200');
            $response->resolve();
            return $response;
        }

        //------
        //------

        //接口请求
        try {
            $client = new Client();
            $result = $client->request($request->method, $request->gateway, $request->option);
            $body = $result->getBody()->getContents();

            $this->responseLogs($this->requestId, $body);

            $status = $result->getStatusCode();

            if ($status != 200 && $this->errorThrow) {
                $response->setBody($body);
                throw new \Exception($body);
            }

            $response->setCode($result->getStatusCode())
                ->setHeader($result->getHeaders())
                ->setBody($body)
                ->resolve();
            return $response;
        } catch (GuzzleException|\Exception $e) {
            $this->responseLogs($this->requestId, $e->getMessage());
            $response->setCode('500')
                ->setError($e->getMessage());
            return $response;
        }

    }

    private function buildUrl()
    {

        if ($this->route) {
            $this->gateway .= '/' . $this->route;
        }

        if ($this->method == RequestMethod::GET and $this->bizParam) {

            $this->gateway .= '?' . http_build_query($this->bizParam);
            $this->bizParam = '';
            unset($this->option['body']);
        }
    }

    private function buildMethod()
    {
        if ($this->async) {
            $this->method .= 'Async';
        }
    }

    /**
     * 构建请求数据
     * @return void
     */
    private function buildOptions()
    {
        $this->option['verify'] = false;
        $this->option['http_errors'] = false;

        if ($this->headers) {
            $this->option['headers'] = $this->headers;
        }

        //if ($this->body) {
        //    $this->option['body'] = $this->body;
        //}

        if ($this->cookie) {
            $this->option['cookies'] = $this->cookie;
        }

        if ($this->timeout) {
            $this->option['connect_timeout'] = $this->timeout;
            $this->option['timeout'] = $this->timeout;
        }

        if ($this->httpDebug) {
            $this->option['debug'] = true;
        }

        if ($this->format == RequestFormat::FORM) {
            $this->option['form_params'] = $this->bizParam;
        }
        if ($this->format == RequestFormat::JSON) {
            $this->option['json'] = $this->bizParam;
        }
        if ($this->format == RequestFormat::RAW) {
            $this->option['body'] = $this->bizParam;
        }
        if ($this->format == RequestFormat::MUL) {
            $this->option['multipart'] = $this->bizParam;

        }
        if ($this->proxy) {
            $this->option['proxy'] = $this->proxy;

            if ($this->proxyPW and $this->proxyAccount) {
                //代理 curl 设置账号密码
                $this->option['curl'] = [CURLOPT_PROXYUSERPWD => "{$this->proxyAccount}:{$this->proxyPW}"];
            }
        }
    }

    protected function bindSoapOptions()
    {
        if ($this->proxy) {
            $this->option['proxy_host'] = substr($this->proxy, 0, strpos($this->proxy, ":"));

            $this->option['proxy_port'] = substr($this->proxy, strpos($this->proxy, ":") + 1);

            if ($this->proxyAccount and $this->proxyPW) {
                $this->option['proxy_login'] = $this->proxyAccount;
                $this->option['proxy_password'] = $this->proxyPW;
            }
        }
    }

    protected function mkLogsDir()
    {

        $fileName = $this->logsDir . DIRECTORY_SEPARATOR . date('Ym');


        if (!is_dir($fileName)) {
            @mkdir($fileName, 0755, true);
        }

        $file = date('Ymd') . '.logs';

        $this->logsFile = $fileName . '/' . $file;
    }

    public function requestLogs($uuid,$inLog = true)
    {
        if (!$this->logsFile) {
            return;
        }

        if ($this->urlTip) {
            $url = $this->gateway;
            $urlLogs = date('Y-m-d H:i:s') . " FUN_TIPS " . $uuid . " " . $this->urlTip . ' ' . $url;
        } else {
            $urlLogs = date('Y-m-d H:i:s') . " URL      " . $uuid . " " . $this->gateway;
        }

        file_put_contents($this->logsFile, $urlLogs . "\r\n", FILE_APPEND);

        //header 日记
        if ($this->headers) {
            $encLogs = date('Y-m-d H:i:s') . " HEADER   " . $uuid . " " . json_encode($this->getHeaders(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            file_put_contents($this->logsFile, $encLogs . "\r\n", FILE_APPEND);
        }

        if (!$inLog) {
            return;
        }

        if ($this->preParameter != $this->bizParam) {
            if($this->urlTip == '影像上传接口'){
                return;
            }
            $encLogs = date('Y-m-d H:i:s') . " ENCRYPT  " . $uuid . " " . json_encode($this->preParameter, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            file_put_contents($this->logsFile, $encLogs . "\r\n", FILE_APPEND);
        }

        if ($this->bizParam ?? '') {
            $biz = $this->bizParam;
            if(is_array($biz)) foreach ($biz as &$val){
                if (is_object($val)) {
                    continue;
                }
                if(($val['name'] ?? '') == 'file'){
                    $val['contents'] = 'resource...';
                }
            }

            if (is_array($biz)) {
                $biz = json_encode($biz, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            }

            $reqLogs = date('Y-m-d H:i:s') . " REQUEST  " . $uuid . " " . $biz;
            file_put_contents($this->logsFile, $reqLogs . "\r\n", FILE_APPEND);
        }
    }

    public function responseLogs($uuid, $data)
    {
        if (!$this->logsFile) {
            return;
        }
        $data = str_replace(["\r\n"],[''],$data);
        $repLogs = date('Y-m-d H:i:s') . " RESPONSE " . $uuid . " " . $data;

        file_put_contents($this->logsFile, $repLogs . "\r\n", FILE_APPEND);
    }

    public function decryptLogs($uuid, $data)
    {
        $decLogs = date('Y-m-d H:i:s') . " DECRYPT  " . $uuid . " " . $data;
        $decLogs = str_replace(["\r\n","\r","\n","\t"],['','','',''],$decLogs);
        file_put_contents($this->logsFile, $decLogs . "\r\n", FILE_APPEND);
    }
}
